
#include "OccView.h"

#include <AIS_Trihedron.hxx>

//------模型加载工具类
IMPLEMENT_STANDARD_RTTIEXT(CModel,AIS_Shape)

CModel::CModel(const TopoDS_Shape &_shape)
    :AIS_Shape(_shape),m_model_name("Unnamed"),m_model_type(MODEL_COMPONENT)
{}

CModel::CModel(const QString _filepath)
    :AIS_Shape(TopoDS_Shape()),m_model_name("Unnamed"),m_model_type(MODEL_COMPONENT)
{
    // 提取文件名字，作为模型名字
    QString t_model_name = _filepath;
    t_model_name.remove(QRegularExpression("(.*/)|([.].+)"));
    m_model_name = t_model_name;
    //从外部文件中加载模型
    Importer t_importer;
    const aiScene *t_scene=t_importer.ReadFile(_filepath.toStdString(),aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);
    if(!t_scene || t_scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !t_scene->mRootNode) // if is Not Zero
    {
        qDebug() << "ERROR::ASSIMP:: " << t_importer.GetErrorString();
        return;
    }
    // 构造根节点及所有子节点
    m_process_nodes(t_scene->mRootNode, t_scene, true);
}

void CModel::m_process_nodes(const aiNode *_node, const aiScene *_scene, bool _is_root)
{
    Graphic3d_MaterialAspect t_occ_material;
    //[0] 模型名字信息
    QString t_node_name = _node->mName.C_Str();
    //[1] 坐标系信息
    aiMatrix4x4 t_matrix=_node->mTransformation;    // 获取转换坐标系
    // 获取旋转矩阵的缩放比例
    ai_real t_scaling_x = aiVector3D(t_matrix.a1,t_matrix.a2,t_matrix.a3).Length();
    ai_real t_scaling_y = aiVector3D(t_matrix.b1,t_matrix.b2,t_matrix.b3).Length();
    ai_real t_scaling_z = aiVector3D(t_matrix.c1,t_matrix.c2,t_matrix.c3).Length();

    // 从 aiMatrix4x4 转换成 gp_Trsf 形式
    gp_Trsf t_transfer;
    t_transfer.SetValues(t_matrix.a1 / t_scaling_x, t_matrix.a2 / t_scaling_x, t_matrix.a3 / t_scaling_x, t_matrix.a4,
                         t_matrix.b1 / t_scaling_y, t_matrix.b2 / t_scaling_y, t_matrix.b3 / t_scaling_y, t_matrix.b4,
                         t_matrix.c1 / t_scaling_z, t_matrix.c2 / t_scaling_z, t_matrix.c3 / t_scaling_z, t_matrix.c4);
    //[2] 拓扑形状信息
    // 构造拓扑形状
    BRepBuilderAPI_Sewing t_sewing_tool;
    t_sewing_tool.Init (1.0e-06, Standard_True);
    // 复合拓扑结构
    TopoDS_Compound t_compound;
    BRep_Builder t_build_tool;
    t_build_tool.MakeCompound (t_compound);
    TopoDS_Face t_topo_face;    // 储存拓扑面
    // 遍历节点的所有网格
    for(unsigned int imesh = 0; imesh < _node->mNumMeshes; imesh++)
    {
        aiMesh* t_mesh = _scene->mMeshes[_node->mMeshes[imesh]];    // 获取当前网格
        // 遍历网格的所有面
        for(unsigned int iface = 0; iface < t_mesh->mNumFaces; iface++)
        {
            t_mesh->mMaterialIndex;
            aiFace t_face = t_mesh->mFaces[iface];
            BRepBuilderAPI_MakePolygon t_polygon;
            // 遍历面的所有顶点
            for(unsigned int ivertex = 0; ivertex < t_face.mNumIndices; ivertex++)
            {
                // 转换顶点储存模式
                gp_Pnt t_pnt=gp_Pnt(t_mesh->mVertices[t_face.mIndices[ivertex]].x,
                                      t_mesh->mVertices[t_face.mIndices[ivertex]].y,
                                      t_mesh->mVertices[t_face.mIndices[ivertex]].z);
                t_polygon.Add(t_pnt);   // 添加顶点
            }
            t_polygon.Close();  // 闭合顶点
            t_topo_face = BRepBuilderAPI_MakeFace (t_polygon); // 通过闭合的线构造面
            if(!t_topo_face.IsNull())
            {
                t_build_tool.Add (t_compound, t_topo_face);  // 将面加入到复合体中
            }
        }
        //材质信息
        aiMaterial* material = _scene->mMaterials[t_mesh->mMaterialIndex];   //通过索引获取网格在环境中的材质
        t_occ_material = m_material_transfer(material); // 从ASSIMP格式转换到OCC材质格式
    }
    t_sewing_tool.Load (t_compound);
    t_sewing_tool.Perform();
    TopoDS_Shape t_topo_shape = t_sewing_tool.SewedShape();
    if (t_topo_shape.IsNull())
    {
        t_topo_shape = t_compound;
    }
    bool t_is_next_root = false;    // 下一处理的节点是否根节点
    //分别处理根节点和子节点
    if(_is_root)
    {
        // 根节点无形状、只有一个子节点、无孙节点
        if(_node->mNumChildren == 1 && _node->mNumMeshes ==0 && _node->mChildren[0]->mNumChildren == 0)
        {
            t_is_next_root = true;  // 将子节点提升为根节点
            m_set_model_type(MODEL_COMPONENT);
        }
        else if(_node->mNumMeshes == 0)
        {
            TopoDS_Shape t_vertex_topo = BRepBuilderAPI_MakeVertex(t_transfer.TranslationPart());
            SetShape(t_vertex_topo);
            m_set_model_type(MODEL_COMP_GROUP);
        }
        else
        {
            SetShape(t_topo_shape); // 设置拓扑形状
        }
        SetLocalTransformation(t_transfer); // 设置模型位姿
        SetMaterial(t_occ_material);
    }
    else
    {
        if(_node->mNumMeshes>0)
        {
            Handle(CModel) t_child = new CModel(t_topo_shape);  // 设置拓扑形状
            t_child->m_set_model_name(t_node_name); // 设置模型名字
            t_child->SetLocalTransformation(t_transfer);    // 设置模型位姿
            t_child->SetMaterial(t_occ_material);
            t_child->m_set_model_type(MODEL_COMPONENT);
            AddChild(t_child);  // 将以上模型作为本对象的子节点
        }
        else
        {}
    }
    // 遍历子节点
    for(unsigned int i = 0; i < _node->mNumChildren; i++)
    {
        m_process_nodes(_node->mChildren[i], _scene , t_is_next_root);   // 构造子节点
    }
}

//模型材质转换，由ASSIMP转成OCC表示方式
Graphic3d_MaterialAspect CModel::m_material_transfer(aiMaterial *_material)
{
    // 声明并初始化OCC材质参数
    Graphic3d_MaterialAspect t_result;
    t_result.SetMaterialType(Graphic3d_MATERIAL_PHYSIC);
    Quantity_Color t_occ_colors[Graphic3d_TypeOfReflection_NB];
    t_occ_colors[Graphic3d_TOR_AMBIENT]  = Quantity_Color (Graphic3d_Vec3 (0.2f, 0.2f, 0.2f));
    t_occ_colors[Graphic3d_TOR_DIFFUSE]  = Quantity_Color (Graphic3d_Vec3 (0.2f, 0.2f, 0.2f));
    t_occ_colors[Graphic3d_TOR_SPECULAR] = Quantity_Color (Graphic3d_Vec3 (1.0f, 1.0f, 1.0f));
    Standard_ShortReal t_occ_shininess = 0.039f;

    aiString name;  // 材质名称 原始数据
    if (AI_SUCCESS==aiGetMaterialString(_material,AI_MATKEY_NAME,&name))
    {
        t_result.SetMaterialName(name.C_Str());
    }
    // 环境光
    aiColor4D ambient;      // 环境光 原始数据
    if(AI_SUCCESS ==aiGetMaterialColor(_material, AI_MATKEY_COLOR_AMBIENT, &ambient))
    {
        t_occ_colors[Graphic3d_TOR_AMBIENT]=Quantity_Color(ambient.r,ambient.g,ambient.b,Quantity_TOC_RGB);
        t_result.SetAmbientColor(t_occ_colors[Graphic3d_TOR_AMBIENT]);
    }
    // 漫反射
    aiColor4D diffuse;      // 漫反射 原始数据
    if(AI_SUCCESS ==aiGetMaterialColor(_material, AI_MATKEY_COLOR_DIFFUSE, &diffuse))
    {
        t_occ_colors[Graphic3d_TOR_DIFFUSE]=Quantity_Color(diffuse.r,diffuse.g,diffuse.b,Quantity_TOC_RGB);
        t_result.SetDiffuseColor(t_occ_colors[Graphic3d_TOR_DIFFUSE]);
    }
    // 镜面光
    aiColor4D specular;     // 镜面光 原始数据
    if(AI_SUCCESS ==aiGetMaterialColor(_material, AI_MATKEY_COLOR_SPECULAR, &specular))
    {
        t_occ_colors[Graphic3d_TOR_SPECULAR]=Quantity_Color(specular.r,specular.g,specular.b,Quantity_TOC_RGB);
        t_result.SetSpecularColor(t_occ_colors[Graphic3d_TOR_SPECULAR]);
    }
    // 反光度
    float shininess;        // 反光度 原始数据
    if(AI_SUCCESS ==aiGetMaterialFloat(_material, AI_MATKEY_SHININESS, &shininess))
    {
        t_occ_shininess=shininess/128.0;    // 由OpenGL值转换成VRML97
        // OCC的反光度表示方式只接受0到1之间，否则报错
        t_occ_shininess = t_occ_shininess<1.0 ? t_occ_shininess:1.0;
        t_occ_shininess = t_occ_shininess<0.0 ? 0.0:t_occ_shininess;
        t_result.SetShininess(t_occ_shininess); // 设置反光度
    }
    return t_result;
}

//使用QMatrix4x4矩阵设置模型位姿
void CModel::m_set_pose_by_matrix(QMatrix4x4 _matrix)
{
    gp_Trsf t_transfer;
    // 从 QMatrix4x4 转换成 gp_Trsf 形式
    t_transfer.SetValues(_matrix(0,0),_matrix(0,1),_matrix(0,2),_matrix(0,3),
                         _matrix(1,0),_matrix(1,1),_matrix(1,2),_matrix(1,3),
                         _matrix(2,0),_matrix(2,1),_matrix(2,2),_matrix(2,3));
    // 设置模型的位姿
    SetLocalTransformation(t_transfer);
}

//获取整个模型的AABB包围盒，包括子模型
Bnd_Box CModel::m_get_full_aabb()
{
    Bnd_Box t_box(BoundingBox());
    t_box = t_box.Transformed(Transformation());
    for(PrsMgr_ListOfPresentableObjectsIter i(Children());i.More();i.Next())
    {
        // 获取当前模型
        Handle(PrsMgr_PresentableObject) t_object = i.Value();
        // 若为CModel类型则转换为CModel
        if(t_object->IsKind(STANDARD_TYPE(CModel)))
        {
            Handle(CModel) t_child_model =  Handle(CModel)::DownCast(t_object);
            Bnd_Box t_child_box = t_child_model->BoundingBox();
            t_child_box = t_child_box.Transformed(t_child_model->Transformation());
            t_box.Add(t_child_box);
        }
    }
    return t_box;
}

//导出模型
bool CModel::m_export_model(QString _filename, const char *_format_id,Handle(AIS_InteractiveContext) _context)
{
    Exporter exporter;
    // 定义场景
    aiScene *t_scene = new aiScene();
    // 单一材质

    // 创建根节点
    t_scene->mRootNode=new aiNode();
    // 创建子节点
    int t_NumChildrenNode = _context->NbSelected();
    aiNode **t_node_list=new aiNode*[t_NumChildrenNode];

    t_scene->mNumMaterials=t_NumChildrenNode;
    t_scene->mMaterials = new aiMaterial*[t_NumChildrenNode];

    // 定义场景所有网格
    t_scene->mNumMeshes = t_NumChildrenNode;
    t_scene->mMeshes = new aiMesh*[t_NumChildrenNode];

    int t_index = 0;
    for ( _context->InitSelected(); _context->MoreSelected(); _context->NextSelected() )
    {
        aiNode *t_node = t_node_list[t_index] = new aiNode();
        t_node->mNumMeshes=1;   // 一个网格
        t_node->mNumChildren=0; // 无子节点
        t_node->mMeshes = new uint[1];  //一个网格地址
        t_node->mMeshes[0] = t_index; // 网格地址索引

        aiMesh* pMesh = t_scene->mMeshes[t_index] = new aiMesh(); // 创建地址0的网格
        pMesh->mMaterialIndex = t_index;  // 网格材质

        Standard_Integer aNbNodes = 0;
        Standard_Integer aNbTriangles = 0;

        Handle(AIS_InteractiveObject) obj = _context->SelectedInteractive();

        //        if ( obj->IsKind( STANDARD_TYPE( AIS_Shape ) ) )
        //        {
        Handle(AIS_Shape) ais_shape = Handle(AIS_Shape)::DownCast(obj);

        Graphic3d_MaterialAspect shpae_material(ais_shape->Material());

        aiMaterial* pMaterial = t_scene->mMaterials[t_index] = new aiMaterial();

        Quantity_Color amb=shpae_material.AmbientColor();
        aiColor4D ambient(amb.Red(),amb.Green(),amb.Blue(),1.0);
        pMaterial->AddProperty(&ambient,1,AI_MATKEY_COLOR_AMBIENT);


        Quantity_Color diff=shpae_material.DiffuseColor();
        aiColor4D diffuse(diff.Red(),diff.Green(),diff.Blue(),1.0);
        pMaterial->AddProperty(&diffuse,1,AI_MATKEY_COLOR_DIFFUSE);

        Quantity_Color spec=shpae_material.SpecularColor();
        aiColor4D specular(spec.Red(),spec.Green(),spec.Blue(),1.0);
        pMaterial->AddProperty(&specular,1,AI_MATKEY_COLOR_SPECULAR);

        Standard_ShortReal shin=shpae_material.Shininess();
        pMaterial->AddProperty(&shin,1,AI_MATKEY_SHININESS);

        TopoDS_Shape theShape = ais_shape->Shape();

        //        }


        // 计算节点和三角形的总数
        for (TopExp_Explorer anExpSF (theShape, TopAbs_FACE); anExpSF.More(); anExpSF.Next())
        {
            TopLoc_Location aLoc;
            Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (TopoDS::Face (anExpSF.Current()), aLoc);
            if (! aTriangulation.IsNull())
            {
                aNbNodes += aTriangulation->NbNodes ();
                aNbTriangles += aTriangulation->NbTriangles ();
            }
        }

        pMesh->mNumVertices = aNbNodes;
        pMesh->mNumFaces = aNbTriangles;
        aiVector3D* vp,*vn;
        vp = pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
        vn = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
        pMesh->mFaces = new aiFace[pMesh->mNumFaces];


        int index=0;
        int face_index=0;
        // 填充临时三角测量
        Standard_Integer aNodeOffset = 0;
        for (TopExp_Explorer anExpSF (theShape, TopAbs_FACE); anExpSF.More(); anExpSF.Next())
        {
            TopLoc_Location aLoc;
            Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (TopoDS::Face (anExpSF.Current()), aLoc);

            auto aNodes = aTriangulation->InternalNodes();
            auto aTriangles = aTriangulation->InternalTriangles();

            // 复制节点
            gp_Trsf aTrsf = aLoc.Transformation();
            for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter)
            {
                gp_Pnt aPnt = aNodes [aNodeIter];
                aPnt.Transform (aTrsf);
                qDebug()<<"nodes "<<aPnt.X()<<aPnt.Y()<<aPnt.Z();
                vp[index].Set(aPnt.X(),aPnt.Y(),aPnt.Z());
                vn[index].Set(0.0,0.0,1.0);
                index++;
            }

            // 复制三角形
            const TopAbs_Orientation anOrientation = anExpSF.Current().Orientation();
            for (Standard_Integer aTriIter = aTriangles.Lower(); aTriIter <= aTriangles.Upper(); ++aTriIter)
            {
                Poly_Triangle aTri = aTriangles (aTriIter);

                Standard_Integer anId[3];
                aTri.Get (anId[0], anId[1], anId[2]);
                if (anOrientation == TopAbs_REVERSED)
                {
                    // 交换 1, 2.
                    Standard_Integer aTmpIdx = anId[1];
                    anId[1] = anId[2];
                    anId[2] = aTmpIdx;
                }
                // 更新节点偏移量
                anId[0] += aNodeOffset;
                anId[1] += aNodeOffset;
                anId[2] += aNodeOffset;
                aiFace& face = pMesh->mFaces[face_index++];
                face.mIndices = new unsigned int[face.mNumIndices = 3];
                face.mIndices[0]=anId[0]-1;
                face.mIndices[1]=anId[1]-1;
                face.mIndices[2]=anId[2]-1;
            }
            aNodeOffset += aNodes.Size();
        }
        t_index++;
    }

    // 根节点加入子节点
    t_scene->mRootNode->addChildren(t_NumChildrenNode,t_node_list);

    exporter.Export(t_scene , _format_id , _filename.toStdString());

    return true;

}

//----窗口类
OccView::OccView(QWidget *parent) : QWidget(parent)
{
    //配置QWidget
    setBackgroundRole( QPalette::NoRole );  //无背景
    setMouseTracking( true );   //开启鼠标位置追踪

    setAttribute(Qt::WA_PaintOnScreen);//直接在屏幕上绘制其内容
    setAttribute(Qt::WA_NoSystemBackground);//不要为窗口自动填充系统背景颜色
    setFocusPolicy(Qt::StrongFocus);//设置了焦点策略为StrongFocus，表示可以通过键盘触发QContextMenuEvent事件
    setUpdatesEnabled(true);//启用更新，这意味着当窗口的内容发生变化时，会触发重绘操作。

    this->resize(parent->size());
    this->m_initialize_context();

    aHSequenceOfShape = new TopTools_HSequenceOfShape;
    undoStack=new QStack<Handle(TopTools_HSequenceOfShape)>;
    selectionStack=new QStack<Handle(AIS_Selection)>;
}

OccView::~OccView()
{
    allPoint.clear();
    delete undoStack;  // 释放堆栈内存
    delete selectionStack;//释放堆栈内存
}

//初始化
void OccView::m_initialize_context()
{
    // 若交互式上下文为空，则创建对象
    if (m_context.IsNull())
    {
        // 此对象提供与X server的连接，在Windows和Mac OS中不起作用
        Handle(Aspect_DisplayConnection) m_display_donnection = new Aspect_DisplayConnection();
        // 创建OpenGl图形驱动
        if (m_graphic_driver.IsNull())
        {
            m_graphic_driver = new OpenGl_GraphicDriver(m_display_donnection);
        }
        //获取QWidget的窗口系统标识符
        WId window_handle = (WId) winId();

#ifdef _WIN32
        // 创建Windows NT 窗口
        Handle(WNT_Window) wind = new WNT_Window((Aspect_Handle)window_handle);
#else \ \
        // 创建XLib window 窗口
        Handle(Xw_Window) wind = new Xw_Window(m_display_donnection, (Window)window_handle);
#endif \
        // 创建3D查看器
        m_viewer = new V3d_Viewer(m_graphic_driver);
        // 创建视图
        m_view = m_viewer->CreateView();
        m_view->SetWindow(wind);

        // 打开窗口
        if (!wind->IsMapped())
        {
            wind->Map();
        }
        m_context = new AIS_InteractiveContext(m_viewer);  // 创建交互式上下文
        // 配置查看器的光照
        m_viewer->SetDefaultLights();
        m_viewer->SetLightOn();
        // 设置视图的背景颜色为黑色
        m_view->SetBackgroundColor(Quantity_NOC_BLACK);
        //-----高亮样式
        m_context->HighlightStyle(Prs3d_TypeOfHighlight_LocalDynamic)->SetColor(Quantity_NameOfColor::Quantity_NOC_RED);//设置高亮样式的颜色为红色
        m_context->HighlightStyle(Prs3d_TypeOfHighlight_LocalDynamic)->SetMethod(Aspect_TOHM_COLOR);//设置高亮样式的方法
        m_context->HighlightStyle(Prs3d_TypeOfHighlight_LocalDynamic)->SetDisplayMode(1);//设置高亮样式的显示模式为1（使用实体显示模式）
        m_context->HighlightStyle(Prs3d_TypeOfHighlight_LocalDynamic)->SetTransparency(0.1f);//设置高亮样式的透明度为0.5（半透明）
        m_context->UpdateCurrentViewer();
        m_context->SetDisplayMode(AIS_Shaded, Standard_True);

        // 显示视方体
        showGraphic3d();
        m_view->Redraw();
    }
}

void OccView::paintEvent(QPaintEvent *event)
{
    QWidget::paintEvent(event);
    m_view->Redraw();
}

void OccView::resizeEvent(QResizeEvent *event)
{
    QWidget::resizeEvent(event);
    if (!m_view.IsNull())
    {
        m_view->MustBeResized();
    }
}

//鼠标按下事件
void OccView::mousePressEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton)
    {
        // 鼠标左键按下：初始化旋转
        m_view->StartRotation(event->position().x(), event->position().y());

    }
    else if (event->buttons() & Qt::RightButton)
    {
        // 鼠标右键按下：初始化平移
        m_x_max = event->position().x();
        m_y_max = event->position().y();
        m_view->Update();
    }
    // 处理选择操作
    if (event->buttons() & Qt::LeftButton)
    {
        if (qApp->keyboardModifiers() == Qt::ControlModifier)
        {
            undoStack->push(aHSequenceOfShape);// 保存操作前的状态
            selectionStack->push(m_context->Selection());
            currentSelection=m_context->Selection();
            // 单选
            m_context->SelectDetected();
            this->selecteShape();
            SaveCurrentSelection();
        }
        else if (qApp->keyboardModifiers() == (Qt::ControlModifier | Qt::ShiftModifier))
        {
            undoStack->push(aHSequenceOfShape);// 保存操作前的状态
            selectionStack->push(m_context->Selection());
            currentSelection=m_context->Selection();
            // 多选
            m_context->SelectDetected(AIS_SelectionScheme_Add);
            this->multiselecteShape();
            SaveCurrentSelection();
        }
    }
    if (event->buttons() & Qt::MiddleButton){
        this->save();
    }
}

void OccView::mouseReleaseEvent(QMouseEvent *event)
{

}


//鼠标移动事件
void OccView::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::RightButton)
    {
        // 鼠标右键长按：执行平移
        m_view->Pan(event->pos().x() - m_x_max, m_y_max - event->pos().y());
        m_x_max = event->position().x();
        m_y_max = event->position().y();
    }
    else if (event->buttons() & Qt::LeftButton)
    {
        // 鼠标左键长按：执行旋转
        m_view->Rotation(event->position().x(), event->position().y());
    }
    else
    {
        Standard_Integer xPix = event->pos().x(); // 获取鼠标 X 坐标
        Standard_Integer yPix = event->pos().y(); // 获取鼠标 Y 坐标

        //qDebug()<<"x:"<<xPix<<"y:"<<yPix;
        m_context->MoveTo(event->pos().x(), event->pos().y(), m_view, Standard_True);
        m_view->Update();
    }
}

//鼠标缩放
void OccView::wheelEvent(QWheelEvent *event)
{
    //当鼠标滚轮滚动时，调用onMouseWheel函数，并传递鼠标按钮的信息、滚动的角度变化以及鼠标滚轮的位置。
    onMouseWheel(event->buttons(),event->angleDelta().y(), event->position().toPoint());
}


//放大缩小
void OccView::onMouseWheel( const int /*theFlags*/, const int theDelta, const QPoint thePoint )
{
    Standard_Integer aFactor = 16;//定义了一个缩放因子 aFactor，用于控制缩放的速度。

    Standard_Integer aX = thePoint.x();//获取鼠标滚轮的位置的 X 坐标并存储到 aX 变量中。
    Standard_Integer aY = thePoint.y();//获取鼠标滚轮的位置的 Y 坐标并存储到 aY 变量中。

    if (theDelta > 0)//根据 theDelta 的值，判断滚轮滚动的方向。如果 theDelta 大于 0，表示鼠标向前滚动，将 aX 和 aY 分别增加 aFactor 的值；
    {
        aX += aFactor;
        aY += aFactor;
    }
    else//如果 theDelta 小于等于 0，表示鼠标向后滚动，将 aX 和 aY 分别减少 aFactor 的值。
    {
        aX -= aFactor;
        aY -= aFactor;
    }
    m_view->Zoom(thePoint.x(), thePoint.y(), aX, aY);//根据滚轮滚动的位置和计算得到的新位置进行缩放操作
}

//键盘按下事件
void OccView::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Delete)
    {
        clearModels();
    }
    else if (event->key() == Qt::Key_Z && (event->modifiers() & Qt::ControlModifier))
    {
        //m_context->SelectDetected(AIS_SelectionScheme_Clear);//清空当前选择
        undo();  // 调用撤销功能
    }
    else if(event->key() == Qt::Key_D && (event->modifiers() & Qt::ControlModifier)){
        showCurrentSelect();//展示当前选择的
    }
    else if(event->key()==Qt::Key_Down){
        CyclicViewChange();
    }
    else
    {
        QWidget::keyPressEvent(event);
    }
}

QPaintEngine *OccView::paintEngine() const
{
    return 0;
}


//多选择
void OccView::multiselecteShape()
{
    qDebug()<<"多选";
    TopoDS_Shape selectedShape=this->m_context->DetectedShape();
    if(!selectedShape.IsNull()){
        this->m_context->NbSelected();
        aHSequenceOfShape->Append(selectedShape);
    }
}

//单选择
void OccView::selecteShape()
{
    aHSequenceOfShape->Clear();
    qDebug()<<"单选!";
    TopoDS_Shape selectedShape=this->m_context->DetectedShape();
    if(!selectedShape.IsNull()){
        this->m_context->NbSelected();
        aHSequenceOfShape->Append(selectedShape);
    }
}

//撤销选择
void OccView::undo() {
    m_context->ClearSelected(false);
    aHSequenceOfShape->Clear();
    if (!mySelectionHistory.empty()) {
        qDebug()<<"undo";
        RestorePreviousSelection();
        currentSelection=selectionStack->pop();
    } else {
        QMessageBox::warning(this, "警告", "没有可撤销的操作!");
    }
}

//显示原点在世界坐标系中的位置
void OccView::showModelOrigin(TopoDS_Shape shape)
{
    // 假设 'shape' 是导入的模型的顶级 TopoDS_Shape 对象
    TopLoc_Location location = shape.Location();
    gp_Trsf transformation = location.Transformation();

    // 获取模型原点在世界坐标系中的位置
    gp_Pnt origin = transformation.TranslationPart();

    // 设置 x 轴方向为 (1, 0, 0)
    gp_Dir aixX(1, 0, 0); // x 方向

    // 设置 z 轴方向为 (0, 0, 1)
    gp_Dir aixZ(0, 0, 1); // z 方向

    // 构造 gp_Ax2
    gp_Ax2 ax = gp_Ax2(origin, aixZ, aixX);
    Handle(Geom_Axis2Placement) TrihedronAxis = new Geom_Axis2Placement(ax);
    Handle(AIS_Trihedron) partTrihedron = new AIS_Trihedron(TrihedronAxis);

    // 设置三坐标轴的大小
    Standard_Real size = 30.0; // 设置大小，例如 10.0
    partTrihedron->SetSize(size);

    // 设置轴的颜色
    Quantity_Color xAxisColor(Quantity_NOC_RED);    // X轴颜色为红色
    Quantity_Color yAxisColor(Quantity_NOC_GREEN);  // Y轴颜色为绿色
    Quantity_Color zAxisColor(Quantity_NOC_BLUE);   // Z轴颜色为蓝色

    partTrihedron->SetXAxisColor(xAxisColor);
    partTrihedron->SetYAxisColor(yAxisColor);
    partTrihedron->SetAxisColor(zAxisColor);

    // 显示三坐标轴
    this->m_get_context()->Display(partTrihedron, Standard_True);

    // 创建表示原点的点
    Handle(AIS_Point) aisOriginPoint = new AIS_Point(new Geom_CartesianPoint(origin));
    this->m_get_context()->Display(aisOriginPoint, Standard_True);
}

// 显示视方体
void OccView::showGraphic3d()
{
    Handle(AIS_ViewCube) aisViewCube = new AIS_ViewCube;
    m_context->SetDisplayMode(AIS_Shaded, true); // 设置显示模式为阴影
    aisViewCube->SetBoxColor(Quantity_NOC_GRAY75);
    aisViewCube->SetSize(55);
    aisViewCube->SetFontHeight(12);
    aisViewCube->SetTransformPersistence(new Graphic3d_TransformPers(
        Graphic3d_TMF_TriedronPers,
        Aspect_TOTP_LEFT_LOWER,
        Graphic3d_Vec2i(100, 100)
        ));
    m_context->Display(aisViewCube, Standard_True);

    //m_view->TriedronDisplay(Aspect_TOTP_LEFT_LOWER, Quantity_NOC_GOLD, 0.08, V3d_ZBUFFER); //显示三坐标轴
}

//切换视角
void OccView::CyclicViewChange()
{
    // 保存视图的顺序
    static int currentViewIndex = 0;

    // 根据 currentViewIndex 选择对应的视图
    switch (currentViewIndex)
    {
    case 0: // Top view
        m_view->SetProj(V3d_Zpos);
        break;
    case 1: // Bottom view
        m_view->SetProj(V3d_Zneg);
        break;
    case 2: // Left view
        m_view->SetProj(V3d_Xneg);
        break;
    case 3: // Right view
        m_view->SetProj(V3d_Xpos);
        break;
    case 4: // Front view
        m_view->SetProj(V3d_Yneg);
        break;
    case 5: // Back view
        m_view->SetProj(V3d_Ypos);
        break;
    }

    // 更新 currentViewIndex 以循环切换视图
    currentViewIndex = (currentViewIndex + 1) % 6;
}


//增加选择
void OccView::AddSelect(const Handle(SelectMgr_EntityOwner)& theObject) {
    AIS_StatusOfPick status = m_context->AddSelect(theObject);
    if (status == AIS_SOP_NothingSelected) {
        cout << "No objects were selected." << endl;
    } else if (status == AIS_SOP_OneSelected) {
        cout << "One object was selected." << endl;
    } else if (status == AIS_SOP_SeveralSelected) {
        cout << "Several objects were selected." << endl;
    }
}

//保存当前选择
void OccView::SaveCurrentSelection() {
    vector<Handle(SelectMgr_EntityOwner)> currentSelection;
    for (m_context->InitSelected();m_context->MoreSelected(); m_context->NextSelected()) {
        currentSelection.push_back(m_context->SelectedOwner());
    }
    mySelectionHistory.push(currentSelection);
}

//撤销选择
void OccView::RestorePreviousSelection() {
    const auto& previousSelection = mySelectionHistory.pop();
    for (const auto& owner : previousSelection) {
        m_context->AddSelect(owner);
    }

    aHSequenceOfShape=undoStack->pop();
    cout << "selectedShape" << endl;
    m_context->UpdateSelected(Standard_True);
    // 重绘视图
    m_view->Redraw();
}

//显示当前选择的形状
void  OccView::showCurrentSelect(){
    if (!aHSequenceOfShape->IsEmpty()) {
        // 移除当前显示的所有对象
        m_context->RemoveAll(Standard_True);

        // 重新显示前一个状态的形状
        for (const auto& shape : aHSequenceOfShape->Sequence()) {
            Handle(AIS_Shape) aisShape = new AIS_Shape(shape);
            m_context->Display(aisShape, Standard_True);
        }
        // 恢复选择状态
        m_context->SetSelection(currentSelection);
        m_context->UpdateSelected(Standard_True);
        showGraphic3d();
        // 重绘视图
        m_view->Redraw();
    } else {
        QMessageBox::warning(this, "警告", "没有选择的内容!");
    }
}

// 保存
void OccView::save()
{
    qDebug() << "保存....";
    qDebug() << "选择项大小->Length: " << aHSequenceOfShape->Length();
    if(aHSequenceOfShape->Length()!=0){
        // 遍历 aHSequenceOfShape 中的元素
        for (int i = 1; i <= aHSequenceOfShape->Length(); i++)
        {
            TopoDS_Shape shape = aHSequenceOfShape->Value(i);
            TopAbs_ShapeEnum shapeType = shape.ShapeType();

            if (shapeType == TopAbs_EDGE) // 选择边
            {
                qDebug() << "TopAbs_EDGE: 选择边";
                TopoDS_Edge edge = TopoDS::Edge(shape);
                if (edge.IsNull())
                {
                    qDebug() << "edge error";
                    continue;
                }
                Standard_Real first, last;
                Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, first, last);
                GeomAdaptor_Curve adaptor(curve);
                GeomAbs_CurveType curveType = adaptor.GetType();
                if (curve.IsNull())
                {
                    qDebug() << "curve error";
                    continue;
                }
                if (curveType == 0) // 直线
                {
                    GeomAdaptor_Curve adaptor(curve);
                    GeomAbs_CurveType curveType = adaptor.GetType();
                    qDebug() << "Geom_Line-->直线"<<curveType;
                    vector<TopoDS_Vertex> vertices;
                    // 获取 edge 的顶点
                    TopExp_Explorer vertexExplorer(edge, TopAbs_VERTEX);
                    while (vertexExplorer.More())
                    {
                        TopoDS_Vertex vertex = TopoDS::Vertex(vertexExplorer.Current());
                        vertices.push_back(vertex);
                        vertexExplorer.Next();
                    }
                    if (vertices.size() < 2)
                    {
                        qDebug() << "line error: not enough vertices";
                        continue;
                    }
                    vector<gp_Pnt> lineTemp;
                    gp_Pnt startPoint = BRep_Tool::Pnt(vertices[0]);//起点
                    lineTemp.push_back(startPoint);// 总是最前写入起点
                    gp_Pnt endPoint = BRep_Tool::Pnt(vertices[1]);//终点
                    gp_Vec direction(startPoint, endPoint);//方向
                    Handle(Geom_Line) line = Handle(Geom_Line)::DownCast(curve);
                    // 计算直线的向量和长度
                    gp_Vec lineVec(startPoint, endPoint);
                    // 确保至少有两个点（起点和终点）
                    numPoints = max(numPoints, 2);
                    // 生成并保存中间点（如果有的话）
                    if (numPoints > 2) {
                        for (int i = 1; i < numPoints - 1; ++i) {
                            double t = static_cast<double>(i) / (numPoints - 1);
                            gp_Pnt point = startPoint.Translated(lineVec * t);
                            lineTemp.push_back(point);
                        }
                    }
                    // 总是最后写入终点
                    lineTemp.push_back(endPoint);
                    allPoint.push_back(lineTemp);
                }
                else if (curveType == 1) // 圆线
                {
                    Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(curve);
                    if (circle.IsNull())
                    {
                        qDebug() << "不是有效的圆或圆弧";
                        return;
                    }
                    // 获取边的参数范围
                    Standard_Real first, last;
                    BRep_Tool::Range(edge, first, last);

                    // 计算圆弧的角度（弧度）
                    Standard_Real arcAngle = last - first;

                    // 圆的半径
                    Standard_Real radius = circle->Radius();

                    const Standard_Real fullCircle = 2 * M_PI;
                    const Standard_Real halfCircle = M_PI;
                    const Standard_Real quarterCircle = M_PI / 2;

                    // 容差值，用于浮点数比较
                    const Standard_Real angleTolerance = 1e-7;

                    string arcType;
                    if (abs(arcAngle - fullCircle) < angleTolerance)
                        arcType = "完整圆";
                    else if (abs(arcAngle - halfCircle) < angleTolerance)
                        arcType = "半圆";
                    else if (abs(arcAngle - quarterCircle) < angleTolerance)
                        arcType = "四分之一圆";
                    else if (arcAngle > halfCircle)
                        arcType = "大圆弧";
                    else
                        arcType = "小圆弧";

                    qDebug()<<"圆线的类型："<< QString::fromStdString(arcType);
                    // 计算曲线的几何属性
                    GProp_GProps props;
                    BRepGProp::LinearProperties(edge, props);
                    Standard_Real totalLength = props.Mass();

                    // 计算间隔长度
                    Standard_Real intervalLength = totalLength / numPoints;

                    // 使用 GeomAdaptor_Curve 将 Geom_Circle 转换为适配器曲线
                    GeomAdaptor_Curve adaptorCurve(circle);

                    // 使用 GCPnts_UniformAbscissa 生成均匀分布的点
                    GCPnts_UniformAbscissa abscissa(adaptorCurve, intervalLength, first, last);
                    if (!abscissa.IsDone()) {
                        qDebug() << "无法生成均匀分布的点";
                        return;
                    }

                    vector<gp_Pnt> Temp;
                    for (Standard_Integer i = 1; i < abscissa.NbPoints(); ++i) {
                        gp_Pnt point = circle->Value(abscissa.Parameter(i));
                        Temp.push_back(point);
                    }
                    // 添加一些额外的信息
                    // gp_Pnt center = circle->Location();
                    // gp_Dir normal = circle->Axis().Direction();
                    // qDebug() << "圆心坐标：(" << center.X() << ", " << center.Y() << ", " << center.Z() << ")";
                    // qDebug() << "法向量：(" << normal.X() << ", " << normal.Y() << ", " << normal.Z() << ")";
                    // qDebug() << "总长度：" << totalLength;
                    // qDebug() << "采样点数：" << Temp.size();

                    // 将采样点添加到全局容器中
                    allPoint.push_back(Temp);
                }else if (curveType == 6) // B 样条曲线
                {
                    qDebug() << "Geom_BSplineCurve-->B 样曲线";
                    Handle(Geom_BSplineCurve) bsplineCurve = Handle(Geom_BSplineCurve)::DownCast(curve);
                    if (bsplineCurve.IsNull())
                    {
                        qDebug() << "bsplineCurve error: ";
                        continue;
                    }
                    vector<gp_Pnt> Temp;
                    Standard_Real totalLength = 0.0;
                    // 创建一个 TopoDS_Edge 对象
                    TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(bsplineCurve);
                    // 计算曲线的几何属性
                    GProp_GProps props;
                    BRepGProp::LinearProperties(edge, props);
                    totalLength = props.Mass();
                    // 计算间隔长度
                    Standard_Real intervalLength = totalLength / numPoints;

                    // 使用 GeomAdaptor_Curve 将 Geom_BSplineCurve 转换为适配器曲线
                    GeomAdaptor_Curve adaptorCurve(bsplineCurve);
                    // 使用 GCPnts_UniformAbscissa 生成均匀分布的点
                    GCPnts_UniformAbscissa abscissa(adaptorCurve, intervalLength);
                    if (!abscissa.IsDone()) {
                        qDebug() << "无法生成均匀分布的点";
                        return;
                    }
                    for (Standard_Integer i = 1; i < abscissa.NbPoints(); ++i) {
                        gp_Pnt point = bsplineCurve->Value(abscissa.Parameter(i));
                        Temp.push_back(point);
                    }
                    allPoint.push_back(Temp);
                }else if(curveType == 7){//偏移边
                    qDebug() << "偏移边:";
                }
                else // 其他类型的边
                {
                    qDebug() << "其他类型的边: ";
                    continue;
                }
            }
            else if (shapeType == TopAbs_VERTEX) // 选择顶点
            {
                qDebug() << "TopAbs_VERTEX-->选择顶点 ";
                TopoDS_Vertex vertex = TopoDS::Vertex(shape);
                gp_Pnt point = BRep_Tool::Pnt(vertex);
                vector<gp_Pnt> Temp;
                Temp.push_back(point);
                allPoint.push_back(Temp);
            }
            else if (shapeType == TopAbs_FACE) // 选择面
            {
                qDebug() << "TopAbs_FACE-->选择面";
                TopoDS_Face face = TopoDS::Face(shape);
                this->saveFaceAsStl(face);
            }
        }
        if(!allPoint.empty()){
            this->sava3DPoint(allPoint);//保存三维坐标
            allPoint.clear();
        }
        qDebug() << "保存完成";
        //保存成功进行容器重置
        aHSequenceOfShape->Clear();
        undoStack->clear();
        selectionStack->clear();
        mySelectionHistory.clear();
        m_context->ClearSelected(false);
    }else{
        QMessageBox::warning(this, "警告", "未选择!");
    }
}


// 保存面为 STL 文件
void OccView::saveFaceAsStl(const TopoDS_Face& face)
{
    QString fileName = QFileDialog::getSaveFileName(this, "Save STL File", "", "STL Files (*.stl)");
    if (fileName.isEmpty()) return;
    TopoDS_Shape shape = face;
    BRepMesh_IncrementalMesh(shape, 0.1); // 网格化
    StlAPI_Writer stlWriter;
    stlWriter.Write(shape, fileName.toStdString().c_str()); // 写入 STL 文件
    QMessageBox::information(this, "Success", "Face saved as STL file.");
}
//保存 直线 3维坐标x y z 为txt格式
void OccView::sava3DPoint(vector<vector<gp_Pnt>> linePoint)
{
    QString fileName = QFileDialog::getSaveFileName(this, "Save TXT File", "", "TXT Files (*.txt)");
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qDebug() << "无法打开文件进行写入";
        return;
    }
    QTextStream out(&file);
    try {
        // 遍历外部向量
        for (const auto& subVector : linePoint) {
            // 遍历内部向量中的每个点
            for (const auto& point : subVector) {//一条线的
                out << point.X() << ", " << point.Y() << ", " << point.Z() << "\n";
            }
        }
        file.close();
        QMessageBox::information(this, "Success", QString("%1 points saved as TXT file.").arg(numPoints));
    }
    catch (Standard_Failure& e) {
        qDebug() << "Exception: " << e.GetMessageString();
        file.close();
        QMessageBox::warning(this, "Error", "Failed to save points.");
    }
}

//清空加入的模型
void OccView::clearModels()
{
    if (!m_context.IsNull())
    {
        m_context->EraseAll(Standard_True); // 清除所有显示的模型

        showGraphic3d(); // 重新显示视方体

        //容器重置
        undoStack->clear();
        selectionStack->clear();
        mySelectionHistory.clear();
        aHSequenceOfShape->Clear(); // 清除形状序列
        m_view->Redraw(); // 重新绘制视图
    }
}

//加载模型文件
void OccView::loadFileModel()
{
    //清空之前导入的模型
    this->clearModels();

    // 获取ASSIMP支持的导入格式
    Importer t_importer;
    string szOut;
    t_importer.GetExtensionList(szOut); // ASSIMP支持的导入格式
    QString supportedExtensions = QString::fromStdString(szOut);
    // 筛选文件格式
    QString t_assimp=tr("ASSIMP (") +QString::fromStdString(szOut)+"*.stp;*.step;*.igs" +tr(")");
    QString all_filter;
    all_filter+=t_assimp;
    // 获取被打开的文件路径
    QString filename = QFileDialog::getOpenFileName(this,tr("open file"),"E:/models",all_filter);
    if(filename.isEmpty())  // 若文件名为空，则不执行操作
    {
        return;
    }else{
        QFileInfo fileInfo(filename);
        QString extension = fileInfo.suffix();
        qDebug()<<extension;
        if(extension=="stp"||extension=="step"||extension=="STP"||extension=="STEP"){
            STEPControl_Reader reader;
            IFSelect_ReturnStatus status = reader.ReadFile(filename.toUtf8().constData());
            if (status == IFSelect_RetDone)
            {
                Standard_Integer NbRoots = reader.NbRootsForTransfer();// 获取可传输根节点的数量
                Standard_Integer NbTrans = reader.TransferRoots();// 传输所有可传输根节点，并返回成功翻译的数量
                // translates all transferable roots, and returns the number of //successful translations
                TopoDS_Shape aShape = reader.OneShape();

                //显示模型坐标原点
                showModelOrigin(aShape);

                Handle(AIS_Shape) anAisModel = new AIS_Shape(aShape);
                anAisModel->SetColor(Quantity_NOC_CHOCOLATE);
                anAisModel->SetTransparency(0.9);// 设置透明度为0.1（即10%透明

                this->m_get_context()->Display(anAisModel, Standard_True);// 显示形状
                this->m_get_context()->Deactivate();
                const int aSubShapeSelMode = AIS_Shape::SelectionMode(TopAbs_FACE);//将选择模式设置为AIS_Shape::SelectionMode(TopAbs_FACE)（选择面）
                this->m_get_context()->Activate(anAisModel, aSubShapeSelMode);
                this->m_get_context()->Activate(anAisModel, AIS_Shape::SelectionMode(TopAbs_SOLID));//将选择模式分别设置为选择实体
                this->m_get_context()->Activate(anAisModel, AIS_Shape::SelectionMode(TopAbs_VERTEX));//选择顶点
                this->m_get_context()->Activate(anAisModel, AIS_Shape::SelectionMode(TopAbs_EDGE));//选择边
                //this->m_get_context()->Activate(anAisModel, AIS_Shape::SelectionMode(TopAbs_WIRE));//选择环
                //this->m_get_context()->Activate(anAisModel, AIS_Shape::SelectionMode(TopAbs_SHAPE));//选择shape
                this->m_get_view()->FitAll(); // 适应所有形状 调整视图的投影和缩放，以使得场景中的所有对象都能完整显示在视图中。

            }else{
                // 不支持的文件类型
                QMessageBox::critical(this, tr("Error"), tr("Unsupported file type: .%1").arg(extension));
                return;
            }
        }else if(extension=="obj"){
            // 不支持的文件类型
            QMessageBox::critical(this, tr("Error"), tr("Unsupported file type: .%1").arg(extension));
            return;
        }
        else if(extension=="igs"||extension=="IGS"){
            IGESControl_Reader myIgesReader;
            Standard_Integer nIgesFaces, nTransFaces;
            if (myIgesReader.ReadFile(filename.toUtf8().constData())!= IFSelect_RetDone) //load the file
            {
                qDebug() << "Couldn't read igs file  \n";
                return;
            }
            Handle(TColStd_HSequenceOfTransient) myList = myIgesReader.GiveList("iges-faces");
            nIgesFaces = myList->Length();
            nTransFaces = myIgesReader.TransferList(myList);
            TopoDS_Shape aShape = myIgesReader.OneShape();
            //显示模型坐标原点
            showModelOrigin(aShape);


            Handle(AIS_Shape) anAisModel = new AIS_Shape(aShape);
            anAisModel->SetColor(Quantity_NOC_CHOCOLATE);
            anAisModel->SetTransparency(0.9);
            this->m_get_context()->Display(anAisModel, Standard_True); // 显示形状
            this->m_get_context()->Deactivate();
            this->m_get_context()->Activate(anAisModel, AIS_Shape::SelectionMode(TopAbs_FACE));//选择面
            this->m_get_context()->Activate(anAisModel, AIS_Shape::SelectionMode(TopAbs_SOLID));//将选择模式分别设置为选择实体
            this->m_get_context()->Activate(anAisModel, AIS_Shape::SelectionMode(TopAbs_VERTEX));//选择顶点
            this->m_get_context()->Activate(anAisModel, AIS_Shape::SelectionMode(TopAbs_EDGE));//选择边
            this->m_get_view()->FitAll();//调整视图的投影和缩放，以使得场景中的所有对象都能完整显示在视图中。

        }else if(extension=="stl"||extension=="STL"){
            TopoDS_Shape shape;
            Handle(Poly_Triangulation) triangulation;
            // 读取 STL 文件
            StlAPI_Reader stlReader;
            if (!stlReader.Read(shape, filename.toUtf8().constData()))
            {
                QMessageBox::critical(this, tr("Error"), tr("Failed to read STL file: %1").arg(filename));
                return;
            }

            //显示模型坐标原点
            showModelOrigin(shape);

            // 创建 AIS_Shape
            Handle(AIS_Shape) anAisModel = new AIS_Shape(shape);
            anAisModel->SetColor(Quantity_NOC_CHOCOLATE);
            anAisModel->SetTransparency(0.9);
            // 显示和设置选择模式
            this->m_get_context()->Display(anAisModel, Standard_True);
            this->m_get_context()->Deactivate();
            this->m_get_context()->Activate(anAisModel, AIS_Shape::SelectionMode(TopAbs_FACE));//选择面
            this->m_get_context()->Activate(anAisModel, AIS_Shape::SelectionMode(TopAbs_SOLID));//将选择模式分别设置为选择实体
            this->m_get_context()->Activate(anAisModel, AIS_Shape::SelectionMode(TopAbs_VERTEX));//选择顶点
            this->m_get_context()->Activate(anAisModel, AIS_Shape::SelectionMode(TopAbs_EDGE));//选择边
            this->m_get_view()->FitAll();//调整视图的投影和缩放，以使得场景中的所有对象都能完整显示在视图中。
        }
        else if (supportedExtensions.contains("*." + extension)){//ASSIMP导入的模型文件
            CModel *t_model = new CModel(filename); // 创建模型
            this->m_get_context()->Display(t_model,true);  // 显示模型
            t_model->SetColor(Quantity_NOC_CHOCOLATE);//设置模型颜色
            t_model->SetTransparency(0.9);

            //显示模型坐标原点
            showModelOrigin(t_model->Shape());

            this->m_get_context()->Deactivate();
            const int aSubShapeSelMode = AIS_Shape::SelectionMode(TopAbs_FACE);//将选择模式设置为AIS_Shape::SelectionMode(TopAbs_FACE)（选择面）
            this->m_get_context()->Activate(t_model, aSubShapeSelMode);
            this->m_get_context()->Activate(t_model, AIS_Shape::SelectionMode(TopAbs_VERTEX));//选择顶点
            this->m_get_context()->Activate(t_model, AIS_Shape::SelectionMode(TopAbs_EDGE));//选择边
            // 选择整个导入的模型
            for(PrsMgr_ListOfPresentableObjectsIter i(t_model->Children());i.More();i.Next())
            {
                // 获取当前模型
                Handle(PrsMgr_PresentableObject) t_object = i.Value();
                // 若为CModel类型则转换为CModel
                if(t_object->IsKind(STANDARD_TYPE(CModel)))
                {
                    Handle_CModel t_child_model =  Handle(CModel)::DownCast(t_object);
                    // 选择该模型（注：不选择过模型就AddSelect可能会出错）
                    this->m_get_context()->SetSelected(t_child_model,true);
                }
            }
            // 选择该模型
            this->m_get_context()->SetSelected(t_model,true);
            // 三维界面显示该模型的全部
            this->m_get_view()->FitAll(t_model->m_get_full_aabb());//调整视图的投影和缩放，以使得场景中的所有对象都能完整显示在视图中。

        }else{
            // 不支持的文件类型
            QMessageBox::critical(this, tr("Error"), tr("Unsupported file type: .%1").arg(extension));
            return;
        }
    }
}




